package com.example.demo;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: Administrator
 * @Date: 2020/12/24 17:34
 */
public class WrapApp extends Thread {

    private volatile Object ctx;
    private volatile Condition condition;
    private volatile boolean running = true;


    private String[] args;
    private ReentrantLock lock = new ReentrantLock();

    public WrapApp(String[] args){
        this.args = args;
    }

    @Override
    public void run() {
        int current = 1;
        while(running){
            File appDir = null;
            try {
                current =  current == 0 ? 1 : 0;
                File file = new File(String.format("C:\\Users\\Administrator\\Downloads\\wukongcrm-72crm-java-master\\demo\\target\\demo-0.0.1-SNAPSHOT%d.jar", current));
                appDir = new File(file.getParentFile(), IdUtil.objectId());
                ZipUtil.unzip(file, appDir);
                File clzDir = new File(appDir, "BOOT-INF\\classes");
                File jarsDir = new File(appDir, "BOOT-INF\\lib");
                URL[] urls = Arrays.stream(jarsDir.listFiles())
                    .map(e -> {
                        try {
                            return file.toURI().toURL();
                        } catch (MalformedURLException malformedURLException) {
                            malformedURLException.printStackTrace();
                        }
                        return null;
                    })
                    .filter(Objects::nonNull)
                    .toArray(URL[]::new);
                URLClassLoader child = null;
                    child = new URLClassLoader(
                        urls,
                        this.getClass().getClassLoader()
                    ){
                        @Override
                        public Class<?> loadClass(String name) throws ClassNotFoundException {
                            Class clzz = findLoadedClass(name);
                            if(clzz != null){
                                return clzz;
                            }
                            File clz = new File(clzDir, name.replaceAll("\\.", "/") + ".class");
                            if (clz.exists()){
                                byte[] bs = FileUtil.readBytes(clz);
                                return defineClass(bs, 0, bs.length);
                            }
                            return super.loadClass(name);
//                            return getSystemClassLoader().loadClass(name);
                        }

                    };

//                ProductLoader loader = new ProductLoader(new URL[]{}, ClassLoader.getSystemClassLoader());
//                loader.addJar("C:\\Users\\Administrator\\Downloads\\wukongcrm-72crm-java-master\\demo\\target\\demo-0.0.1-SNAPSHOT.jar");
                Thread.currentThread().setContextClassLoader(child);
                Class<?> clz = child.loadClass("com.example.demo.DemoApplication");
                Class<?> app = child.loadClass("org.springframework.boot.SpringApplication");
                Method method = app.getDeclaredMethod("run", Class.class, String[].class);
                ctx = (method.invoke(null, clz, (Object) args));
                System.out.println(ctx);

                lock.lock();
                condition = lock.newCondition();
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                if(loader instanceof URLClassLoader){
                    try {
                        ((URLClassLoader) loader).close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                FileUtil.del(appDir);
            }

        }
    }

    public  boolean refresh(){
        try{
            lock.lock();
            boolean success = end();
            if(!success){
                return false;
            }
            condition.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }

    private  boolean end(){
        try {
            lock.lock();
            Method method = ctx.getClass().getSuperclass().getDeclaredMethod("doClose");
            method.setAccessible(true);
            method.invoke(ctx);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            lock.unlock();
        }
        return true;
    }


}
